package com.lincolnXmypcqq.cmds.framework;

import com.lincoln.framework.factories.ProtocolFactoryBean;
import com.lincolnXmypcqq.cmds.annotation.*;
import com.lincolnXmypcqq.config.ExpectionHandle;
import com.lincolnXmypcqq.robot.framework.RobotDealContext;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author ziyao.peng01@ucarinc.com
 * @description 储存RobotCmd的类
 * @date 2018/11/20 15:11
 **/
public class RobotCmdFactory {
    private static Logger logger = LoggerFactory.getLogger(RobotCmdFactory.class);

    /**
     * 单独执行前置执行的命令(必须排好序,从小到大)
     */
    @Getter
    private static List<RobotCmd> single_msg = new ArrayList<>();

    /**
     * 单独执行好友消息执行的命令(必须排好序,从小到大)
     */
    @Getter
    private static List<RobotCmd> single_friendMsg = new ArrayList<>();

    /**
     * 单独执行讨论组消息执行的命令(必须排好序,从小到大)
     */
    @Getter
    private static List<RobotCmd> single_groupMsg = new ArrayList<>();

    /**
     * 单独执行群消息执行的命令(必须排好序,从小到大)
     */
    @Getter
    private static List<RobotCmd> single_qunMsg = new ArrayList<>();

    /**
     * 单独执行通知消息执行的命令(必须排好序,从小到大)
     */
    @Getter
    private static List<RobotCmd> single_notice = new ArrayList<>();


    /**
     * 前置执行的命令(必须排好序,从小到大)
     */
    @Getter
    private static List<RobotCmd> msg = new ArrayList<>();

    /**
     * 好友消息执行的命令(必须排好序,从小到大)
     */
    @Getter
    private static List<RobotCmd> friendMsg = new ArrayList<>();

    /**
     * 讨论组消息执行的命令(必须排好序,从小到大)
     */
    @Getter
    private static List<RobotCmd> groupMsg = new ArrayList<>();

    /**
     * 群消息执行的命令(必须排好序,从小到大)
     */
    @Getter
    private static List<RobotCmd> qunMsg = new ArrayList<>();

    /**
     * 通知消息执行的命令(必须排好序,从小到大)
     */
    @Getter
    private static List<RobotCmd> notice = new ArrayList<>();

    @Getter
    private static boolean init = false;

    public static void main(String[] args) {
        init();
    }

    /**
     * @return boolean
     * @description 初始化
     * @author ziyao.peng01@ucarinc.com
     * @date 2018/11/20 15:18
     */
    public static boolean init(String... classPaths) {
        for (String classpath : classPaths) {
            scanClass(classpath);
        }
        init = true;
        sortList(single_msg);
        sortList(single_friendMsg);
        sortList(single_groupMsg);
        sortList(single_qunMsg);
        sortList(single_notice);
        sortList(msg);
        sortList(friendMsg);
        sortList(groupMsg);
        sortList(qunMsg);
        sortList(notice);
        return isInit();
    }

    public static void sortList(List<RobotCmd> list) {
        if (list != null && list.size() > 0) {
            list.sort((o1, o2) -> {
                if (o1.getPriority() < o2.getPriority()) {
                    return -1;
                } else if (o1.getPriority() > o2.getPriority()) {
                    return 1;
                } else {
                    return 0;
                }
            });
        }
    }

    /**
     * @param annotation
     * @return boolean
     * @description 判断注解是不是系统内置的几种注解, 例如Msg, FriendMsg, GroupMsg等
     * @author ziyao.peng01@ucarinc.com
     * @date 2018/11/28 16:03
     */
    private static boolean compareAnnotationIsMsg(Annotation annotation) {
        if (Msg.class.equals(annotation.annotationType()) ||
                FriendMsg.class.equals(annotation.annotationType()) ||
                GroupMsg.class.equals(annotation.annotationType()) ||
                QunMsg.class.equals(annotation.annotationType()) ||
                Notice.class.equals(annotation.annotationType())) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * @return void
     * @description 扫描class
     * @author ziyao.peng01@ucarinc.com
     * @date 2018/11/20 15:46
     */
    public static void scanClass(String classPath) {
        try {
            Set<Class<?>> set = ProtocolFactoryBean.getClasses(classPath);
            for (Class clazz : set) {
                Annotation[] annotations = clazz.getAnnotations();
                if (annotations != null && annotations.length > 0) {
                    for (Annotation annotation : annotations) {
                        //找出注解了几个msg注解的
                        if (compareAnnotationIsMsg(annotation)) {
                            RobotCmd robotCmd = new RobotCmd();
                            robotCmd.setClazz(clazz);
                            if (Msg.class.equals(annotation.annotationType())) {
                                robotCmd.setSingle(((Msg) annotation).single());
                                robotCmd.setPriority(((Msg) annotation).priority());
                                if (!findVerifyAndDo(clazz, robotCmd)) {
                                    break;
                                }
                                if (robotCmd.isSingle()) {
                                    addAndSort(single_msg, robotCmd);
                                } else {
                                    addAndSort(msg, robotCmd);
                                }
                            }
                            if (FriendMsg.class.equals(annotation.annotationType())) {
                                robotCmd.setSingle(((FriendMsg) annotation).single());
                                robotCmd.setPriority(((FriendMsg) annotation).priority());
                                if (!findVerifyAndDo(clazz, robotCmd)) {
                                    break;
                                }
                                if (robotCmd.isSingle()) {
                                    addAndSort(single_friendMsg, robotCmd);
                                } else {
                                    addAndSort(friendMsg, robotCmd);
                                }
                            }
                            if (GroupMsg.class.equals(annotation.annotationType())) {
                                robotCmd.setSingle(((GroupMsg) annotation).single());
                                robotCmd.setPriority(((GroupMsg) annotation).priority());
                                if (!findVerifyAndDo(clazz, robotCmd)) {
                                    break;
                                }
                                if (robotCmd.isSingle()) {
                                    addAndSort(single_groupMsg, robotCmd);
                                } else {
                                    addAndSort(groupMsg, robotCmd);
                                }
                            }
                            if (QunMsg.class.equals(annotation.annotationType())) {
                                robotCmd.setSingle(((QunMsg) annotation).single());
                                robotCmd.setPriority(((QunMsg) annotation).priority());
                                if (!findVerifyAndDo(clazz, robotCmd)) {
                                    break;
                                }
                                if (robotCmd.isSingle()) {
                                    addAndSort(single_qunMsg, robotCmd);
                                } else {
                                    addAndSort(qunMsg, robotCmd);
                                }
                            }
                            if (Notice.class.equals(annotation.annotationType())) {
                                robotCmd.setSingle(((Notice) annotation).single());
                                robotCmd.setPriority(((Notice) annotation).priority());
                                if (!findVerifyAndDo(clazz, robotCmd)) {
                                    break;
                                }
                                if (robotCmd.isSingle()) {
                                    addAndSort(single_notice, robotCmd);
                                } else {
                                    addAndSort(notice, robotCmd);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void addAndSort(List<RobotCmd> list, RobotCmd robotCmd) {
        list.add(robotCmd);
        list.sort((o1, o2) -> {
            if (o1.getPriority() < o2.getPriority()) {
                return -1;
            } else if (o1.getPriority() == o2.getPriority()) {
                return 0;
            } else {
                return 1;
            }
        });
        logger.info("扫描到了" + list.size() + "个机器人指令");
    }

    private static boolean findVerifyAndDo(Class clazz, RobotCmd robotCmd) {
        for (Method method : clazz.getMethods()) {
            if (method.getAnnotations() != null && method.getAnnotations().length > 0) {
                for (Annotation a : method.getAnnotations()) {
                    if (Verify.class.equals(a.annotationType())) {
                        robotCmd.setVerify(method);
                    }
                    if (Do.class.equals(a.annotationType())) {
                        robotCmd.setDone(method);
                    }
                }
            }
        }
        if (robotCmd.getVerify() == null || robotCmd.getDone() == null) {
            return false;
        }
        return true;
    }

    /**
     * @param
     * @return java.util.List<com.lincoln.cmds.framework.RobotCmd>
     * @description 返回msg注解的列表
     * @author ziyao.peng01@ucarinc.com
     * @date 2018/11/27 10:48
     */
    public static List<RobotCmd> findRobotCmdMsg() {
        return verify(single_msg, msg);
    }

    /**
     * @param
     * @return java.util.List<com.lincoln.cmds.framework.RobotCmd>
     * @description 通过消息找到对应的指令解析器
     * @author ziyao.peng01@ucarinc.com
     * @date 2018/11/27 10:08
     */
    public static List<RobotCmd> findRobotCmd() {
        Integer msgType = RobotDealContext.getMsgType();
        if (msgType == null) {
            return new ArrayList<>();
        }
        //-1 未定义事件 1 好友信息 2,群信息 3,讨论组信息 4,临时会话 1001,被添加好友 1002,好友在线状态改变 1003 被删除好友
        // 1004 签名变更 2001 某人申请加入群 2002 某人被邀请加入群 2003 我被邀请加入群 2005 某人被批准加入了群 2006 某人退出群  
        // 2007 某人被管理移除群 2008 某群被解散 2009 某人成为管理员 2010 某人被取消管理员 2011 群名片变动 2012 群名变动//暂未解析 2013 群公告变动
        switch (msgType) {
            case -1:
                return new ArrayList<>();
            case 1:
                return verify(single_friendMsg, friendMsg);
            case 2:
                return verify(single_qunMsg, qunMsg);
            case 3:
                return verify(single_groupMsg, groupMsg);
            case 4:
                return verify(single_friendMsg, friendMsg);
            case 1001:
                return verify(single_notice, notice);
            case 1002:
                return verify(single_notice, notice);
            case 1003:
                return verify(single_notice, notice);
            case 1004:
                return verify(single_notice, notice);
            case 2001:
                return verify(single_notice, notice);
            case 2002:
                return verify(single_notice, notice);
            case 2003:
                return verify(single_notice, notice);
            case 2005:
                return verify(single_notice, notice);
            case 2006:
                return verify(single_notice, notice);
            case 2007:
                return verify(single_notice, notice);
            case 2008:
                return verify(single_notice, notice);
            case 2009:
                return verify(single_notice, notice);
            case 2010:
                return verify(single_notice, notice);
            case 2011:
                return verify(single_notice, notice);
            case 2012:
                return verify(single_notice, notice);
            case 2013:
                return verify(single_notice, notice);
            default:
                return new ArrayList<>();
        }
    }

    /**
     * @param single, list, params
     * @return java.util.List<com.lincoln.cmds.framework.RobotCmd>
     * @description 找出某条消息符合验证的所有robotcmd
     * @author ziyao.peng01@ucarinc.com
     * @date 2018/11/28 16:11
     */
    private static List<RobotCmd> verify(List<RobotCmd> single, List<RobotCmd> list) {
        List<RobotCmd> result = new ArrayList<>();
        for (RobotCmd msg : single) {
            if (msg.getVerify() != null) {
                try {
                    if ((boolean) msg.getVerify().invoke(msg.getVerify().getDeclaringClass().newInstance(), RobotDealContext.getParams())) {
                        result.add(msg);
                        return result;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        for (RobotCmd msg : list) {
            if (msg.getVerify() != null) {
                try {
                    if ((boolean) msg.getVerify().invoke(msg.getVerify().getDeclaringClass().newInstance(), RobotDealContext.getParams())) {
                        result.add(msg);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }
}
